package org.mx.spring.time;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import org.mx.spring.task.BaseTask;
import org.mx.spring.task.Task;
import org.mx.spring.task.TaskFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import lombok.Getter;

/**
 * 提供系统时间服务，解决System.currentTimeMillis()在大并发情况下的低效问题
 * 
 * @author john.peng
 *
 */
public class SystemClock {
	private final Logger logger = LoggerFactory.getLogger(SystemClock.class);
	private ScheduledExecutorService scheduler = null;

	private @Getter final long precision;
	private final AtomicLong now;
	private TaskFactory taskFactory;

	/**
	 * 构造函数，默认采用1毫秒的计时精度
	 */
	public SystemClock() {
		this(1L);
	}

	/**
	 * 构造函数，并设置外部的任务工厂
	 * 
	 * @param taskFactory TaskFactory
	 * @see TaskFactory
	 */
	public SystemClock(TaskFactory taskFactory) {
		this(1L);
		this.taskFactory = taskFactory;
	}
	
	/**
	 * 构造函数，设置时钟精度和外部的任务工厂
	 * 
	 * @param precision 时钟精度，单位为毫秒。
	 * @param taskFactory TaskFactory
	 */
	public SystemClock(long precision, TaskFactory taskFactory) {
		this(precision);
		this.taskFactory = taskFactory;
	}

	/**
	 * 构造函数
	 * @param precision 计时精度，单位毫秒
	 */
	public SystemClock(long precision) {
		super();
		this.precision = precision;
		this.now = new AtomicLong(System.currentTimeMillis());
	}

	/**
	 * 初始化线程，开始按照指定精度计时
	 */
	public void init() {
		if (taskFactory == null) {
			scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> {
				Thread thread = new Thread(runnable);
				// 设置为守护线程
				thread.setDaemon(true);
				return thread;
			});
			scheduler.scheduleAtFixedRate(() -> now.set(System.currentTimeMillis()), precision, precision,
					TimeUnit.MILLISECONDS);
		} else {
			taskFactory.addScheduledTask(new BaseTask("systemClock") {
				@Override
				public void invoke() {
					now.set(System.currentTimeMillis());
				}
			}, Task.ScheduledConfig.MS(precision, precision));
		}
		if (logger.isInfoEnabled()) {
			logger.info(String.format("Initialize the SystemClock success, precision: %d ms.", precision));
		}
	}

	/**
	 * 释放线程资源
	 */
	public void close() {
		if (scheduler != null) {
			scheduler.shutdown();
			scheduler = null;
			if (logger.isInfoEnabled()) {
				logger.info("Close the SystemClock thread success.");
			}
		}
	}

	/**
	 * 获取当前时间，单位毫秒
	 * @return 当前时间
	 */
	public long now() {
		return now.get();
	}
}
